<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
    <!-- 百度禁止转码 -->
    <meta http-equiv="Cache-Control" content="no-siteapp" />
    <!-- uc强制竖屏 -->
    <meta name="screen-orientation" content="portrait" />
    <!-- QQ强制竖屏 -->
    <meta name="x5-orientation" content="portrai" />
    <!-- 禁用电话号码邮箱自动识别 -->
    <meta name="format-detection" content="telephone=no,email=no" />
    <title>document</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

      html,
      body {
        height: 100%;
      }

      button {
        appearance: none;
        padding: 3px;
        margin-top: 4px;
      }

      .wrap {
        background-color: #111;
        height: calc(100% - 100px);
      }

      .btn_wrap {
        height: 100px;
        position: relative;
        padding: 10px 60px 0 10px;
      }

      #fps {
        position: absolute;
        right: 10px;
        top: 10px;
        color: rgba(70, 270, 40, 0.8);
      }

      #starCount {
        position: absolute;
        right: 10px;
        top: 40px;
        color: rgba(270, 70, 40, 0.8);
        z-index: 50;
        transform: translateZ(0px);
      }
    </style>
  </head>

  <body>
    <div class="btn_wrap">
      <button id="addStar">添加100星星</button>
      <a href="星星移动动画.html">dom版体验压榨你的设备吧</a>
      <div id="starCount">星星数目: 10</div>
      <div id="fps">FPS: 60</div>
    </div>
    <div class="wrap" id="wrap">
      <canvas id="canvas">
        你的浏览器版本太低
      </canvas>
    </div>
    <script src="./js/tween.js"></script>
    <script src="./js/animation.js"></script>
    <script>
      function ready(fn) {
        if (document.attachEvent ? document.readyState === 'complete' : document.readyState !== 'loading') {
          fn()
        } else {
          document.addEventListener('DOMContentLoaded', fn)
        }
      }

      ready(() => {
        var canvas = document.getElementById('canvas'),
          ctx = canvas.getContext('2d'),
          wrap = document.getElementById('wrap'),
          addStar = document.getElementById('addStar'),
          starCountText = document.getElementById('starCount'),
          fpsWrap = document.getElementById('fps'),
          clientWidth = wrap.clientWidth,
          clientHeight = wrap.clientHeight,
          maxLeft = clientWidth * 0.9,
          maxTop = clientHeight - clientWidth * 0.1,
          imgWidth = Math.floor(clientWidth * 0.1),
          // 星星数量
          starCount = 10,
          // 星星坐标系
          starArr = [],
          // 帧率计算
          frame = 0,
          allFrameCount = 0,
          lastTime = Date.now(),
          lastFameTime = Date.now(),
          now,
          // 绘图次数
          drawCount = 0,
          // canvas动画帧
          fnReq = null,
          // canvas动画延时
          timer = null,
          // 图片
          img = [],
          // 图片已加载完数量
          imgFlag = 0,
          // 离屏绘制
          canvasOffscreen = []
        canvas.width = clientWidth
        canvas.height = clientHeight - 10
        function rAF(callback) {
          window.requestAnimationFrame(callback) || window.webkitRequestAnimationFrame(callback) || window.mozRequestAnimationFrame(callback) || window.setTimeout(callback, 1000 / 60)
        }
        // 计算fps
        function loop() {
          ;(now = Date.now()), (fs = now - lastFameTime), (fps = Math.round(1000 / fs))
          lastFameTime = now
          // 不置 0，在动画的开头及结尾记录此值的差值算出 FPS
          allFrameCount++
          frame++

          if (now > 1000 + lastTime) {
            var fps = Math.round((frame * 1000) / (now - lastTime))
            fpsWrap.innerHTML = `FPS: ${fps}`
            frame = 0
            lastTime = now
          }

          rAF(loop)
        }
        function randomLeft() {
          return Math.floor(Math.random() * maxLeft)
        }
        function randowTop() {
          return Math.floor(Math.random() * maxTop)
        }
        // 获取当前的宽高
        function curImageScale(index) {
          var temp = Math.floor(drawCount / 2) + index + '',
            count = +temp.substring(temp.length - 1)
          return count === 0 ? imgWidth : (imgWidth * count) / 10
        }

        // 计算缩放后的位置
        function scaleCoo(pos, size) {
          return pos + (imgWidth - size) / 2
        }

        // 获取当前图片的位置
        function imgIndex(index) {
          return (index + Math.floor(drawCount / 2)) % 17
        }

        // 绘制图形
        function draw(value) {
          ctx.clearRect(0, 0, clientWidth, clientHeight)
          drawCount++
          for (let index = 0; index < starCount; index++) {
            var _curLeft = starArr[index][0],
              _curTop = starArr[index][1]
            if (value !== 1) {
              // 为1表示动画已经结束，进入延迟阶段
              _curLeft = Math.floor(starArr[index][2] + starArr[index][4] * value)
              _curTop = Math.floor(starArr[index][3] + starArr[index][5] * value)
              starArr[index][0] = _curLeft
              starArr[index][1] = _curTop
            }
            ctx.drawImage(canvasOffscreen[imgIndex(index)], _curLeft, _curTop)
          }
        }

        function drawInit(reset) {
          ctx.clearRect(0, 0, clientWidth, clientHeight)
          if (reset) {
            clearTimeout(timer)
            starArr.splice(0)
            for (let index = 0; index < starCount; index++) {
              var _startLeft = randomLeft(),
                _startTop = randowTop()
              // 六个坐标分别为当前左、当前上、初始左、初始上、左移动距离、上移动距离
              starArr.push([_startLeft, _startTop, _startLeft, _startTop, randomLeft() - _startLeft, randowTop() - _startTop])
            }
          } else {
            for (let index = 0; index < starCount; index++) {
              var _startLeft = starArr[index][0],
                _startTop = starArr[index][1]
              // 六个坐标分别为当前左、当前上、初始左、初始上、左移动距离、上移动距离
              starArr[index] = [_startLeft, _startTop, _startLeft, _startTop, randomLeft() - _startLeft, randowTop() - _startTop]
            }
          }
          animation()
          timer = setTimeout(() => {
            drawInit(false)
          }, 1300)
        }

        // 根据动画函数计算偏移值
        function animation() {
          fnReq && cancelAnimationFrame(fnReq())
          fnReq = Math.animation(0, 1, 'Sine.easeOut', 1300, function(value) {
            draw(value)
          })
        }
        for (let i = 0; i < 17; i++) {
          img[i] = new Image()
          img[i].src = `./images/star_frame-${i}.jpg`
          img[i].onload = function() {
            //第i张图片加载完成
            imgFlag++
            // 离屏绘制
            canvasOffscreen[i] = document.createElement('canvas')
            canvasOffscreen[i].width = imgWidth
            canvasOffscreen[i].height = imgWidth
            canvasOffscreen[i].getContext('2d').drawImage(img[i], 0, 0, imgWidth, imgWidth)
            if (imgFlag === 17) {
              //全部加载完成
              drawInit(true)
            }
          }
        }
        loop()
        window.addEventListener(
          'resize',
          () => {
            clientWidth = wrap.clientWidth
            clientHeight = wrap.clientHeight
            maxLeft = clientWidth * 0.9
            maxTop = clientHeight - clientWidth * 0.1
            imgWidth = Math.floor(clientWidth * 0.1)
            canvas.width = clientWidth
            canvas.height = clientHeight - 10
            drawInit(true)
          },
          false
        )
        addStar.addEventListener(
          'click',
          function(e) {
            e.preventDefault()
            starCount += 100
            drawInit(true)
            starCountText.innerHTML = `星星数目: ${starCount}`
          },
          false
        )
      }, false)
    </script>
  </body>
</html>
